/**
 * Copyright(C) 2008 Matthias Braunhofer
 * All rights reserved
 *
 * Created on: 10.09.2008
 */

package it.cums.ui.dialogs;

import it.cums.ui.Activator;
import it.cums.core.controller.ApplicationController;
import it.cums.core.model.Customer;
import it.cums.core.model.Invoice;
import it.cums.core.model.Order;
import it.cums.core.model.OrderedProduct;
import it.cums.core.model.Product;
import it.cums.core.model.Supplier;
import it.cums.ui.editors.customer.CustomerEditor;
import it.cums.ui.editors.customer.CustomerEditorInput;
import it.cums.ui.editors.order.OrderEditor;
import it.cums.ui.editors.order.OrderEditorInput;
import it.cums.ui.editors.product.ProductEditor;
import it.cums.ui.editors.product.ProductEditorInput;
import it.cums.ui.editors.supplier.SupplierEditor;
import it.cums.ui.editors.supplier.SupplierEditorInput;
import it.cums.ui.localization.Messages;
import it.cums.core.util.Converter;
import it.cums.core.util.InvoiceManager;
import it.cums.core.util.OrderedProductManager;

import java.util.ArrayList;

import org.eclipse.jface.action.Action;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;

public class SearchDialog extends Dialog {
	private Text searchText;
	private Button caseSensitiveButton;
	private Button regularExpressionButton;
	private Button customersButton;
	private Button ordersButton;
	private Button productsButton;
	private Button suppliersButton;
	private Button searchButton;
	private TableViewer viewer;
	private ArrayList<Object> result;
	private Action doubleClickAction;
	
	public SearchDialog(Shell parentShell) {
		super(parentShell);
	}
	
	
	protected Control createContents(Composite parent) {
		parent.setSize(600, 500);
		this.getShell().setText(Messages.SearchDialog_0);
		Rectangle shellBounds = this.getParentShell().getBounds();
	    Point dialogSize = this.getShell().getSize();
	    this.getShell().setLocation(shellBounds.x + (shellBounds.width - dialogSize.x) / 2, shellBounds.y + (shellBounds.height - dialogSize.y) / 2);
	    return super.createContents(parent);
	}

	
	protected Control createDialogArea(Composite parent) {
		GridLayout layout = new GridLayout();
		layout.numColumns = 2;
		parent.setLayout(layout);
		GridData gdHorizontalSpan = new GridData();
		gdHorizontalSpan.horizontalSpan = 2;
		
		Label labelContainingText = new Label(parent, SWT.NONE);
		labelContainingText.setText(Messages.SearchDialog_1);
		labelContainingText.setLayoutData(gdHorizontalSpan);		
		GridData gdFill = new GridData(GridData.FILL_HORIZONTAL);

		searchText = new Text(parent, SWT.BORDER);
		searchText.setLayoutData(gdFill);
		searchText.addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent e) {
				if (searchText.getText().trim().equals("")) { //$NON-NLS-1$
					searchButton.setEnabled(false);
				} else {
					searchButton.setEnabled(true);
				}
			}});
		
		caseSensitiveButton = new Button(parent, SWT.CHECK);
		caseSensitiveButton.setText(Messages.SearchDialog_3);
		
		Label specialCharsLabel = new Label(parent, SWT.NONE);
		specialCharsLabel.setText(Messages.SearchDialog_4);
		specialCharsLabel.setLayoutData(gdFill);
		
		regularExpressionButton = new Button(parent, SWT.CHECK);
		regularExpressionButton.setText(Messages.SearchDialog_5);
		GridData gdFillHorizontal = new GridData(GridData.FILL_HORIZONTAL);
		gdFillHorizontal.horizontalSpan = 2;
		
		Group searchInGroup = new Group(parent, SWT.NONE);
		searchInGroup.setText(Messages.SearchDialog_6);
		searchInGroup.setLayoutData(gdFillHorizontal);
		GridLayout searchInLayout = new GridLayout();
		searchInLayout.numColumns = 4;
		searchInGroup.setLayout(searchInLayout);
		
		customersButton = new Button(searchInGroup, SWT.CHECK);
		customersButton.setText(Messages.SearchDialog_7);
		customersButton.setSelection(true);
		
		ordersButton = new Button(searchInGroup, SWT.CHECK);
		ordersButton.setText(Messages.SearchDialog_8);
		ordersButton.setSelection(true);
		
		productsButton = new Button(searchInGroup, SWT.CHECK);
		productsButton.setText(Messages.SearchDialog_9);
		productsButton.setSelection(true);
		
		suppliersButton = new Button(searchInGroup, SWT.CHECK);
		suppliersButton.setText(Messages.SearchDialog_10);
		suppliersButton.setSelection(true);
		
		GridData gdFillBoth = new GridData(GridData.FILL_BOTH);
		gdFillBoth.horizontalSpan = 2;
		Group resultsGroup = new Group(parent, SWT.NONE);
		resultsGroup.setText(Messages.SearchDialog_11);
		resultsGroup.setLayoutData(gdFillBoth);
		GridLayout resultsLayout = new GridLayout();
		resultsLayout.numColumns = 1;
		resultsGroup.setLayout(resultsLayout);
		
		viewer = new TableViewer(resultsGroup, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FILL);
		viewer.setContentProvider(new ViewContentProvider());
		viewer.setLabelProvider(new ViewLabelProvider());
		viewer.setSorter(new NameSorter());
		viewer.setInput(result);
		viewer.getTable().setLayoutData(gdFillBoth);
		makeActions();
		hookDoubleClickAction();
		
		return parent;
	}
	
	private void makeActions() {
		doubleClickAction = new Action() {
			public void run() {
				ISelection selection = viewer.getSelection();
				Object obj = ((IStructuredSelection)selection).getFirstElement();
				String editorId = ""; //$NON-NLS-1$
				IEditorInput input = null;
				if (obj instanceof Customer) {
					Customer c = (Customer)obj;
					input = new CustomerEditorInput(c);
					editorId = CustomerEditor.ID;
				} else if (obj instanceof Order) {
					Order o = (Order)obj;
					input = new OrderEditorInput(o);
					editorId = OrderEditor.ID;
				} else if (obj instanceof Product) {
					Product p = (Product)obj;
					input = new ProductEditorInput(p);
					editorId = ProductEditor.ID;
				} else if (obj instanceof Supplier) {
					Supplier s = (Supplier)obj;
					input = new SupplierEditorInput(s);
					editorId = SupplierEditor.ID;
				}
				IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
				try {
					page.openEditor(input, editorId);
					// notify any listeners of the view with the actual data of
					// the view
					viewer.setSelection(viewer.getSelection());
				} catch (PartInitException e) {
					Activator.getDefault().logError(e.getMessage(), e);
				}
			}
		};
	}

	
	protected void createButtonsForButtonBar(Composite parent) {
		GridData gridData = new GridData();
		gridData.horizontalSpan = 2;
		gridData.horizontalAlignment = SWT.END;
		parent.setLayoutData(gridData);
		GridLayout layout = new GridLayout();
		layout.numColumns = 2;
		parent.setLayout(layout);
		searchButton = new Button(parent, SWT.PUSH);
		searchButton.setText(Messages.SearchDialog_13);
		searchButton.setEnabled(false);
		searchButton.addSelectionListener(new SelectionAdapter() {
			
			public void widgetSelected(SelectionEvent e) {
				search();
			}});
		
		Button cancelButton = new Button(parent, SWT.PUSH);
		cancelButton.setText(Messages.SearchDialog_14);
		cancelButton.addSelectionListener(new SelectionAdapter() {
			
			public void widgetSelected(SelectionEvent e) {
				close();
			}});
	}
	
	private boolean matches(String string1, String string2) {
		if (!caseSensitiveButton.getSelection()) {
			if (regularExpressionButton.getSelection()) {
				string2 = buildRegex(string2);
				return string1.toLowerCase().matches(string2.toLowerCase());
			} else {
				return string1.toLowerCase().equals(string2.toLowerCase());
			}
		} else {
			if (regularExpressionButton.getSelection()) {
				string2 = buildRegex(string2);
				return string1.matches(string2);
			} else {
				return string1.equals(string2);
			}
		}
	}
	
	private String buildRegex(String string) {
		string = string.replaceAll("\\[", "\\\\["); //$NON-NLS-1$ //$NON-NLS-2$
		string = string.replaceAll("\\{", "\\{"); //$NON-NLS-1$ //$NON-NLS-2$
		string = string.replaceAll("\\^", "\\\\^"); //$NON-NLS-1$ //$NON-NLS-2$
		string = string.replaceAll("\\$", "\\\\$"); //$NON-NLS-1$ //$NON-NLS-2$
		string = string.replaceAll("\\|", "\\\\|"); //$NON-NLS-1$ //$NON-NLS-2$
		string = string.replaceAll("\\)", "\\\\)"); //$NON-NLS-1$ //$NON-NLS-2$
		string = string.replaceAll("\\.", "\\\\."); //$NON-NLS-1$ //$NON-NLS-2$
		string = string.replaceAll("\\+", "\\\\+"); //$NON-NLS-1$ //$NON-NLS-2$
		StringBuffer buffer = new StringBuffer(""); //$NON-NLS-1$
		for(int i = 0; i < string.length(); i++) {
			char currentChar = string.charAt(i);
				if (currentChar == '?') {
					int counter = 0;
					for (int j = i-1; j >= 0; j--) {
						if (string.charAt(j) == '\\') {
							counter++;
						} else {
							break;
						}
					}
					if (counter % 2 != 1) {
						buffer.append(".{1}"); //$NON-NLS-1$
					} else {
						buffer.append("?"); //$NON-NLS-1$
					}
				} else if (currentChar == '*') {
					int counter = 0;
					for (int j = i-1; j >= 0; j--) {
						if (string.charAt(j) == '\\') {
							counter++;
						} else {
							break;
						}
					}
					if (counter % 2 != 1) {
						buffer.append(".*"); //$NON-NLS-1$
					} else {
						buffer.append("*"); //$NON-NLS-1$
					}
				} else {
					buffer.append(currentChar);
				}
		}			
		return buffer.toString();
	}
	
	private void search() {
		result = new ArrayList<Object>();
		String search = searchText.getText();
		if (customersButton.getSelection()) {
			ArrayList<Customer> customers = ApplicationController.getInstance().getCustomers().getCustomers();
			for (Customer customer : customers) {
				if (matches(customer.getName(), search)) {
					result.add(customer);
				} else if (matches(customer.getTaxNumber(), search)) {
					result.add(customer);
				} else if (matches(customer.getReferencePerson(), search)) {
					result.add(customer);
				} else if (matches(customer.getAddress(), search)) {
					result.add(customer);
				} else if (matches(customer.getCap(), search)) {
					result.add(customer);
				} else if (matches(customer.getLocation(), search)) {
					result.add(customer);
				} else if (matches(customer.getCountry().getDescription(), search)) {
					result.add(customer);
				} else if (matches(customer.getPhone(), search)) {
					result.add(customer);
				} else if (matches(customer.getMobilePhone(), search)) {
					result.add(customer);
				} else if (matches(customer.getEmail(), search)) {
					result.add(customer);
				} else if (matches(customer.getWebSite(), search)) {
					result.add(customer);
				} else if (customer.getDeliveryCountry() != null) {
					if (customer.getDeliveryAddress().contains(search)) {
						result.add(customer);
					} else if (matches(customer.getDeliveryCap(), search)) {
						result.add(customer);
					} else if (matches(customer.getDeliveryLocation(), search)) {
						result.add(customer);
					} else if (matches(customer.getDeliveryCountry().getDescription(), search)) {
						result.add(customer);
					}
				} else if (matches(customer.getNotes(), search)) {
					result.add(customer);
				}
			}
		}
		if (ordersButton.getSelection()) {
			ArrayList<Customer> customers = ApplicationController.getInstance().getCustomers().getCustomers();
			for (Customer customer : customers) {
				ArrayList<Order> orders = customer.getOrders().getOrders();
				for (Order order : orders) {
					if (matches(order.getCustomer().getName(), search)) {
						result.add(order);
					} else if (matches(order.getPriority(), search)) {
						result.add(order);
					} else if (matches(order.getStatus(), search)) {
						result.add(order);
					} else if (matches(Converter.convertToString(order.getOrderDate()), search)) {
						result.add(order);
					} else if (searchInInvoices(order, search)) {
						result.add(order);
					} else if (searchInOrderedProducts(order, search)) {
						result.add(order);
					}
				}
			}
		}
		if (suppliersButton.getSelection()) {
			ArrayList<Supplier> suppliers = ApplicationController.getInstance().getSuppliers().getSuppliers();
			for (Supplier supplier : suppliers) {
				if (matches(supplier.getName(), search)) {
					result.add(supplier);
				} else if (matches(supplier.getTaxNumber(), search)) {
					result.add(supplier);
				} else if (matches(supplier.getReferencePerson(), search)) {
					result.add(supplier);
				} else if (matches(supplier.getAddress(), search)) {
					result.add(supplier);
				} else if (matches(supplier.getCap(), search)) {
					result.add(supplier);
				} else if (matches(supplier.getLocation(), search)) {
					result.add(supplier);
				} else if (matches(supplier.getCountry().getDescription(), search)) {
					result.add(supplier);
				} else if (matches(supplier.getPhone(), search)) {
					result.add(supplier);
				} else if (matches(supplier.getMobilePhone(), search)) {
					result.add(supplier);
				} else if (matches(supplier.getEmail(), search)) {
					result.add(supplier);
				} else if (matches(supplier.getWebSite(), search)) {
					result.add(supplier);
				} else if (matches(supplier.getAccountDetails(), search)) {
					result.add(supplier);
				} else if (matches(supplier.getNotes(), search)) {
					result.add(supplier);
				}
			}
		} 
		if (productsButton.getSelection()) {
			ArrayList<Product> products = ApplicationController.getInstance().getProducts().getProducts();
			for (Product product : products) {
				if (matches(product.getManufacturer(), search)) {
					result.add(product);
				} else if (matches(product.getName(), search)) {
					result.add(product);
				} else if (matches(product.getNotes(), search)) {
					result.add(product);
				}
			}
		}
		viewer.refresh();
	}
	
	private boolean searchInInvoices(Order order, String searchText) {
		for (Invoice invoice : InvoiceManager.getInstance().listInvoices(order)) {
			if (matches(invoice.getCondition(), searchText)) {
				return true;
			} else if (matches(Converter.convertToString(invoice.getDueDate()), searchText)) {
				return true;
			} else if (matches(Converter.convertToString(invoice.getPaymentDate()), searchText)) {
				return true;
			} else if (matches(invoice.getStatus(), searchText)) {
				return true;
			} else if (matches(invoice.getType(), searchText)) {
				return true;
			}
		}
		return false;
	}
	
	private boolean searchInOrderedProducts(Order order, String searchText) {
		for (OrderedProduct product : OrderedProductManager.getInstance().listOrderedProducts(order)) {
			if (matches(product.getProduct(), searchText)) {
				return true;
			}
		}
		return false;
	}

	class ViewContentProvider implements IStructuredContentProvider {
		
		public ViewContentProvider() {
			result = new ArrayList<Object>();
		}
		
		public void inputChanged(Viewer v, Object oldInput, Object newInput) {
		}
		
		public void dispose() {
		}
		
		public Object[] getElements(Object parent) {
			return result.toArray();
		}
	}
	
	class ViewLabelProvider extends LabelProvider implements ITableLabelProvider {
		public String getColumnText(Object obj, int index) {
			return obj.toString();
		}
		
		public Image getColumnImage(Object obj, int index) {
			return getImage(obj);
		}
		
		public Image getImage(Object obj) {
			if (obj instanceof Order) {
				return Activator.getImageDescriptor("icons/order.gif").createImage(); //$NON-NLS-1$
			} else if (obj instanceof Product) {
				return Activator.getImageDescriptor("icons/product.gif").createImage(); //$NON-NLS-1$
			} else {
				return Activator.getImageDescriptor("icons/person.gif").createImage(); //$NON-NLS-1$
			}
		}
	}
	
	class NameSorter extends ViewerSorter {
		
		public int compare(Viewer viewer, Object e1, Object e2) {
			// TODO Auto-generated method stub
			return e1.toString().compareTo(e2.toString());
		}
	}
	
	private void hookDoubleClickAction() {
		viewer.addDoubleClickListener(new IDoubleClickListener() {
			public void doubleClick(DoubleClickEvent event) {
				doubleClickAction.run();
			}
		});
	}
}

